package com.jiezuo.common.util;

import com.google.common.collect.Maps;
import com.jiezuo.common.exception.BusinessRuntimeException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.*;

/**
 * @description 多文件上传工具类 + 下载
 * @author 庞留杰
 * @date 2020/8/4 18:09
 * @version V1.0
 **/
@Slf4j
@Component
public class UploadUtils {

    /**
     * 功能描述:
     * @author: 庞留杰
     * @param files   文件
     * @param read_prefix  读取文件url前缀
     * @param save_url     本地文件存放路径
     * @param size    上传文件最大大限制（单位：M）
     * @return: list
     * @date: 2020/8/4 18:07
     */
    public static List<Map<String, String>> upload(MultipartFile[] files, String read_prefix, String save_url, int size) {
        String time = DateTimeUtil.format(new Date(), DateTimeUtil.DATE);
        String uploadPath = save_url + "/" + time;
        List<Map<String, String>> list = new ArrayList();
//        try {
            for (MultipartFile file : files) {
                if (!file.isEmpty()) {// 判断
                    if (file.getName() != null && !file.getName().equals("")) {// 判断是否选择了文件
                        long upFileSize = file.getSize();     //上传文件的大小
                        String fileName = file.getOriginalFilename();//获取文件名
                        // 取得不包含后缀的文件名
                        String name = fileName.substring(0, fileName.lastIndexOf("."));
                        // 取得文件的后缀
                        String suffix = fileName.substring(fileName.lastIndexOf(".") + 1).toUpperCase();
                        //为防止文件名重复覆盖,修改文件名：生成规则 yyyyMMddHHmmssSSS+5位随机数（这种方式对于文件名是“.”的文件会出问题，例如："..xlsx"，"..docx"）
                        // String newName = fileName.replace(name, DateTimeUtil.format(new Date(), DateTimeUtil.YEAR_TO_MILLION) + (int) ((Math.random() * 9 + 1) * 100000));
                        String newName = fileName;
                        if (".".equals(name)) {
                            newName = String.format("%s.%s", DateTimeUtil.format(new Date(), DateTimeUtil.YEAR_TO_MILLION) + (int) ((Math.random() * 9 + 1) * 100000), suffix);
                        } else {
                            newName = fileName.replace(name, DateTimeUtil.format(new Date(), DateTimeUtil.YEAR_TO_MILLION) + (int) ((Math.random() * 9 + 1) * 100000));
                        }
                        System.out.println("newName = " + newName);
                        //上传文件最大值
                        Long maxSize = size * 1024L * 1024L;
                        if (upFileSize > maxSize) {
                            throw new BusinessRuntimeException("您上传的文件太大，请选择不超过" + size + "M的文件");
                        }
                        File saveFile = new File(uploadPath);
                        //判断文件夹是否存在，不存在创建
                        if (!(saveFile.exists() && saveFile.isDirectory())) {
                            saveFile.mkdirs();//支持多级文件夹创建
                        }
                        Path savePath = Paths.get(saveFile.toURI());
                        try {
                            //获取当前文件的真实类型:1 表示图片,2 表示文档,3 表示视频,4 表示种子,5 表示音乐,7 表示其它
                            //Integer fileType = FileTypeUtil.isFileType(FileTypeUtil.getType(file.getInputStream()));
                            /**
                             * ATOMIC_MOVE 原子性的复制
                             * COPY_ATTRIBUTES 将源文件的文件属性信息复制到目标文件中
                             * REPLACE_EXISTING 替换已存在的文件
                             * */
                            Files.copy(file.getInputStream(), savePath.resolve(newName), StandardCopyOption.REPLACE_EXISTING);
                            String fingerprint = FileFingerprintUtil.fileMD5(saveFile + "/" + newName);
                            Map<String, String> map = new HashMap();
                            map.put("name", fileName);//文件名称
                            map.put("size", upFileSize + "");//文件大小
                            map.put("type", suffix);//文件类型
                            map.put("uri", time + "/" + newName);//文件相对路径
                            map.put("url", read_prefix + time + "/" + newName);//文件绝对路径
                            map.put("fingerprint", fingerprint);  // 文件指纹
                            list.add(map);
                        } catch (IOException e) {
                            log.error("对不起，上传失败", e);
                            throw new BusinessRuntimeException("对不起，上传失败");
                        }
                    } else {
                        throw new BusinessRuntimeException("没有选择上传文件");
                    }
                }
            }
//        } catch (Exception e) {
//            log.error("对不起，上传失败", e);
//            throw new BusinessRuntimeException("对不起,上传失败");
//        }
        return list;
    }


    /**
     * 功能描述: 使用URL下载远程文件
     * @author: 庞留杰
     * @param remote_url 远程URL
     * @param target_directory 要保存的文件夹
     * @param file_name 要保存的文件名
     * @return: map
     * @exception
     * @date: 2021/2/3 16:56
     */
    public static Map<String, String> download(String remote_url, String target_directory, String file_name) {
        Map<String, String> map = Maps.newHashMap();
        log.info(" >>>>>> 远程文件路径 >>>>>> " + remote_url);
        URL url = null;
        HttpURLConnection http = null;
        InputStream is = null;
        OutputStream out = null;
        long size = 0;
        try {
            /**
             * 路径处理（文件名中可能有中文或空格）
             *      URLDecoder.decode(str,"UTF-8")解码，若路径中含有+ ，也是不能解决的
             *      需要对+单独处理，转换为%20
             */
            String fileName = remote_url.substring(remote_url.lastIndexOf("/") + 1);//文件名
            String substr = remote_url.substring(0, remote_url.lastIndexOf("/") + 1);
            remote_url = substr + URLEncoder.encode(fileName, "utf-8").replaceAll("\\+", "%20");
            url = new URL(remote_url);
            http = (HttpURLConnection) url.openConnection();
            http.setConnectTimeout(3000);
            // 设置 User-Agent 避免被拦截
            http.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)");
            // 获取文件大小
            long length = http.getContentLengthLong();
            size = (length / 1024);
            log.info(" >>>>>> 文件大小 >>>>>> " + size + "KB");
            is = http.getInputStream();
            byte[] buff = new byte[1024 * 10];
            out = new FileOutputStream(new File(target_directory, file_name));
            int len;
            int count = 0; // 计数
            while ((len = is.read(buff)) != -1) {
                out.write(buff, 0, len);
                out.flush();
                ++count;
            }
        } catch (IOException e) {
            e.printStackTrace();
            throw new BusinessRuntimeException("下载文件失败");
        } finally {
            try {
                // 关闭资源
                out.close();
                is.close();
                http.disconnect();
            } catch (IOException e) {
                e.printStackTrace();
                throw new BusinessRuntimeException("关闭流失败");
            }
        }
        //返回数据
        map.put("name", file_name);//文件名称
        map.put("size", size + "");//文件大小
        String suffix = file_name.substring(file_name.lastIndexOf(".") + 1).toUpperCase();
        map.put("type", suffix);//文件类型
        map.put("uri", target_directory + "/" + file_name);//文件相对路径
        return map;
    }


    public static Boolean download2(String source, String target) {
        boolean boo = false;
        log.info(" >>>>>> 远程文件路径 >>>>>> " + source);
        URL url = null;
        HttpURLConnection http = null;
        InputStream is = null;
        OutputStream out = null;
        long size = 0;
        try {
            /**
             * 路径处理（文件名中可能有中文或空格）
             *      URLDecoder.decode(str,"UTF-8")解码，若路径中含有+ ，也是不能解决的
             *      需要对+单独处理，转换为%20
             */
            String fileName = source.substring(source.lastIndexOf("/") + 1);//文件名
            String substr = source.substring(0, source.lastIndexOf("/") + 1);
            source = substr + URLEncoder.encode(fileName, "utf-8").replaceAll("\\+", "%20");
            url = new URL(source);
            http = (HttpURLConnection) url.openConnection();
            http.setConnectTimeout(3000);
            // 设置 User-Agent 避免被拦截
            http.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)");
            // 获取文件大小
            long length = http.getContentLengthLong();
            size = (length / 1024);
            log.info(" >>>>>> 文件大小 >>>>>> " + size + "KB");
            is = http.getInputStream();
            byte[] buff = new byte[1024 * 10];
            out = new FileOutputStream(new File(target));
            int len;
            int count = 0; // 计数
            while ((len = is.read(buff)) != -1) {
                out.write(buff, 0, len);
                out.flush();
                ++count;
            }
        } catch (IOException e) {
            e.printStackTrace();
            throw new BusinessRuntimeException("下载文件失败");
        } finally {
            try {
                // 关闭资源
                out.close();
                is.close();
                http.disconnect();
            } catch (IOException e) {
                e.printStackTrace();
                throw new BusinessRuntimeException("关闭流失败");
            }
            boo = true;
        }
        //返回数据
        return boo;
    }

}
